class Api {
    constructor() {
        this.user = { id: 1, name: 'test' };
        this.friends = [this.user, this.user, this.user];
        this.photo = 'not a real photo';
    }

    getUser() {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(this.user), 200);
        });
    }

    getFriends(userId) {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(this.friends.slice()), 200);
        });
    }

    getPhoto(userId) {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(this.photo), 200);
        });
    }

    throwError() {
        return new Promise((resolve, reject) => {
            setTimeout(() => reject(new Error('Intentional Error')), 200);
        });
    }
}

function promiseApiInfo() {
    const api = new Api();
    api.getUser()
        .then(arr => {
            console.log(arr);
            return api.getFriends();
        })
        .then(arr => {
            console.log(arr);
            return api.getPhoto();
        })
        .then(arr => {
            console.log(arr);
        })
        .catch(e => console.log(e));
}

function promiseApiInfoParallel() {
    const api = new Api();
    const user = api.getUser();
    api.getFriends(user.id)
        .then(friends => {
            let promiseArr = [];
            for (const friend of friends) {
                promiseArr.push(api.getFriends(friend.id));
            }
            Promise.all(promiseArr)
                .then(arr => {
                    console.log('promiseApiInfoParallel', arr);
                })
                .catch(e => console.log(e));
        })
        .catch(e => console.log(e));
}
promiseApiInfoParallel();

function* genApiInfo() {
    const api = new Api();
    const user = yield api.getUser();
    const friends = yield api.getFriends();
    const photo = yield api.getPhoto();
    return { user, friends, photo };
}

/* let gen = genApiInfo();
gen.next()
    .value.then(user => {
        console.log(user);
        return gen.next().value;
    })
    .then(friends => {
        console.log(friends);
        return gen.next().value;
    })
    .then(photo => {
        console.log(photo);
        return gen.next().value;
    })
    .then(photo => {
        console.log(photo);
    }); */

function run(gen) {
    let g = gen();
    let index = 1;
    function next(data) {
        let result = g.next(data);
        if (result.done) {
            // console.log(result.value);
            return result.value;
        }
        result.value.then(data => {
            console.log(data);
            next(data);
        });
    }
    next();
}

// run(genApiInfo);

async function asyncAwaitIsYourNewBestFriend() {
    const api = new Api();
    const user = await api.getUser();
    const friends = await api.getFriends(user.id);
    const photo = await api.getPhoto(user.id);
    console.log('asyncAwaitIsYourNewBestFriend', { user, friends, photo });
    return { user, friends, photo };
}
// asyncAwaitIsYourNewBestFriend();

async function asyncAwaitLoops() {
    const api = new Api();
    const user = await api.getUser();
    const friends = await api.getFriends(user.id);
    for (const friend of friends) {
        let moreFriends = await api.getFriends(friend.id);
        console.log('asyncAwaitLoops ', moreFriends);
    }
}
// asyncAwaitLoops();

async function asyncAwaitLoopsParallel() {
    try {
        const api = new Api();
        const user = await api.getUser();
        const friends = await api.getFriends(user.id);
        const promistArr = friends.map(data => {
            return api.getFriends(data.id);
        });
        const moreFriends = await Promise.all(promistArr);
        console.log('asyncAwaitLoopsParallel ', moreFriends);
    } catch (error) {
        console.log(error);
    }
}
asyncAwaitLoopsParallel();
